﻿#include "audiofilter.h"

AudioFilter::AudioFilter()
{
    isRun = false;
}

AudioFilter::~AudioFilter()
{
    quit();
    wait();
}

void AudioFilter::setRunState(bool start)
{
    this->isRun = start;

    if(start)
        this->start();
}

void AudioFilter::setAudioParm(AudioParm &parm1, AudioParm &parm2)
{
    this->parmIn1 = std::move(parm1);
    this->parmIn2 = std::move(parm2);
}

void AudioFilter::run()
{
    /****************** 文件操作 *****************/
    FILE *inFile1 = fopen(parmIn1.filePath.c_str(), "rb");
    if(!inFile1)
    {
        printf("fopen inFile1 failed\n");
        return;
    }

    FILE *inFile2 = fopen(parmIn2.filePath.c_str(), "rb");
    if(!inFile2)
    {
        printf("fopen inFile2 failed\n");
        return;
    }

    FILE *outFile = fopen("audioFilter.pcm", "wb");
    if(!outFile)
    {
        printf("fopen audioFilter.pcm failed\n");
        return;
    }

    /****************** 过滤器操作 *****************/
    //创建avfilter_graph
    AVFilterGraph *filterGraph = avfilter_graph_alloc();
    if(filterGraph == nullptr)
        return;

    char args[512] = {0};

    //输入过滤器A1
    const AVFilter *aBufferInFilter1 = avfilter_get_by_name("abuffer");
    snprintf(args, sizeof(args), "sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
             parmIn1.sampleRate, av_get_sample_fmt_name(parmIn1.format), av_get_default_channel_layout(parmIn1.channel));
    qDebug() << "audio input1" << args;
    AVFilterContext *aBufferInFilterCtx1 = avfilter_graph_alloc_filter(filterGraph, aBufferInFilter1, "aBufferInFilter1");
    if(avfilter_init_str(aBufferInFilterCtx1, args) != 0)
    {
        printf("avfilter_init_str(aBufferInFilterCtx1) failed.\n");
        return;
    }

    //输入过滤器2
    const AVFilter *aBufferInFilter2 = avfilter_get_by_name("abuffer");
    snprintf(args, sizeof(args), "sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
             parmIn2.sampleRate, av_get_sample_fmt_name(parmIn2.format), av_get_default_channel_layout(parmIn2.channel));
    qDebug() << "audio input2" << args;
    AVFilterContext *aBufferInFilterCtx2 = avfilter_graph_alloc_filter(filterGraph, aBufferInFilter2, "aBufferInFilter2");
    if(avfilter_init_str(aBufferInFilterCtx2, args) != 0)
    {
        printf("avfilter_init_str(aBufferInFilterCtx2) failed.\n");
        return;
    }

    //输出过滤器
    const AVFilter *aBufferSink = avfilter_get_by_name("abuffersink");
    AVFilterContext *aBufferSinkCtx = avfilter_graph_alloc_filter(filterGraph, aBufferSink, "sink");
    if(aBufferSinkCtx == nullptr)
        return;
    if (avfilter_init_str(aBufferSinkCtx, nullptr) != 0)
    {
        printf("avfilter_init_str(aBufferSinkCtx) failed\n");
        return;
    }

    //混音过滤器
    const AVFilter *amix = avfilter_get_by_name("amix");
    AVFilterContext *mixFilterCtx = avfilter_graph_alloc_filter(filterGraph, amix, "amix");
    if(mixFilterCtx == nullptr)
        return;
    //inputs输入流数量 duration决定流的结束(longest最长输入时间 shortest最短 first第一个输入持续时间) dropout_transition结束时容量重整时间
    snprintf(args, sizeof(args), "inputs=2:duration=%s:dropout_transition=0", "longest");
    if (avfilter_init_str(mixFilterCtx, args) != 0)
    {
        printf("avfilter_init_str(mixFilterCtx) failed.\n");
        return;
    }

    //格式过滤器 固定参数
    const AVFilter *aFormat = avfilter_get_by_name("aformat");
    snprintf(args, sizeof(args), "sample_rates=44100:sample_fmts=%s:channel_layouts=0x%I64x",
             av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), av_get_default_channel_layout(2));
    qDebug() << "audio format" << args;
    AVFilterContext *aFormatCtx = avfilter_graph_alloc_filter(filterGraph, aFormat, "aformat");
    if (avfilter_init_str(aFormatCtx, args) != 0)
    {
        printf("avfilter_init_str(aFormatCtx) failed\n");
        return;
    }

    //开始设置Filter连接关系
    if (avfilter_link(aBufferInFilterCtx1, 0, mixFilterCtx, 0) != 0)
        return;

    if (avfilter_link(aBufferInFilterCtx2, 0, mixFilterCtx, 1) != 0)
        return;

    if (avfilter_link(mixFilterCtx, 0, aFormatCtx, 0) != 0)
        return;

    if (avfilter_link(aFormatCtx, 0, aBufferSinkCtx, 0) != 0)
        return;

    //生效配置
    if (avfilter_graph_config(filterGraph, NULL) < 0)
    {
        printf("avfilter_graph_config() failed.\n");
        return;
    }

    /****************** 音频帧操作 *****************/
    //缓存区
    char pcmInBuffer1[IN_PCM_BUF_SIZE] = {0};
    char pcmInBuffer2[IN_PCM_BUF_SIZE] = {0};
    int oneFrameSize1 = parmIn1.channel * parmIn1.byteSize * 1024;
    int oneFrameSize2 = parmIn2.channel * parmIn2.byteSize * 1024;
    int outFrameSize = 0;

    int len1 = 0;
    int len2 = 0;
    bool finish1 = false;
    bool finish2 = false;

    while(isRun)
    {
        len1 = fread(pcmInBuffer1, 1, oneFrameSize1, inFile1);
        len2 = fread(pcmInBuffer2, 1, oneFrameSize2, inFile2);
        if (len1 > 0 || len2 > 0)
        {
            if(len1 > 0)
            {
                AVFrame *frame = av_frame_alloc();
                frame->sample_rate = parmIn1.sampleRate;
                frame->format = parmIn1.format;
                frame->channel_layout = av_get_default_channel_layout(parmIn1.channel);
                frame->nb_samples = len1 / parmIn1.channel / parmIn1.byteSize;

                av_frame_get_buffer(frame, 1);
                memcpy(frame->extended_data[0], pcmInBuffer1, len1);

                if (av_buffersrc_add_frame(aBufferInFilterCtx1, frame) != 0)
                    qDebug() << "av_buffersrc_add_frame 1 error";

                av_frame_free(&frame);
            }
            else
            {
                if(!finish1)
                {
                    av_buffersrc_add_frame(aBufferInFilterCtx1, NULL);
                    finish1 = true;
                    qDebug() << "audio input1 Finish";
                }
            }

            if(len2 > 0)
            {
                AVFrame *frame = av_frame_alloc();
                frame->sample_rate = parmIn2.sampleRate;
                frame->format = parmIn2.format;
                frame->channel_layout = av_get_default_channel_layout(parmIn2.channel);
                frame->nb_samples = len2 / parmIn2.channel / parmIn2.byteSize;

                av_frame_get_buffer(frame, 1);
                memcpy(frame->extended_data[0], pcmInBuffer2, len2);

                if (av_buffersrc_add_frame(aBufferInFilterCtx2, frame) != 0)
                    qDebug() << "av_buffersrc_add_frame 2 error";

                av_frame_free(&frame);
            }
            else
            {
                if(!finish2)
                {
                    av_buffersrc_add_frame(aBufferInFilterCtx2, NULL);
                    finish2 = true;
                    qDebug() << "audio input2 Finish";
                }
            }
        }
        else
        {
            qDebug() << "All Finish";
            break;
        }

        //接收并写入本地
        AVFrame *outFrame = av_frame_alloc();
        int ret = av_buffersink_get_frame(aBufferSinkCtx, outFrame);
        if(ret < 0)
        {
            qDebug() << "av_buffersink_get_frame error";
            av_frame_free(&outFrame);
            continue;
        }

        //存在重采样 样本大小需重新计算
        outFrameSize = av_samples_get_buffer_size(NULL, outFrame->channels, outFrame->nb_samples, (AVSampleFormat)outFrame->format, 1);
        if(outFrameSize < OUT_PCM_BUF_SIZE)
            fwrite(outFrame->extended_data[0], 1, outFrameSize, outFile);

//        qDebug() << outFrameSize << outFrame->nb_samples << outFrame->sample_rate;
        av_frame_free(&outFrame);
    }

    //释放资源
    fclose(inFile1);
    fclose(inFile2);
    fclose(outFile);

    avfilter_graph_free(&filterGraph);

    isRun = false;
}
